﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Net.Mime;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using Zhp.Auth.IService;
using Zhp.Common.Appsetting;
using Zhp.Common.Helper;
using Zhp.Common.WebApp;
using Zhp.Model.Common;

namespace Zhp.Auth
{
    public class SingleTokenAuthenticationHandler : AuthenticationHandler<SingleTokenOptions>
    {

        public SingleTokenAuthenticationHandler(
            IOptionsMonitor<SingleTokenOptions> options,
            ILoggerFactory logger,
            IOnlineService onlineSvc,
            UrlEncoder encoder) : base(options, logger, encoder)
        {
        }

        protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            string token = Context.Request.Headers[AuthHeaderTypeConst.Authorization].ToString();
            token = token.Replace(JwtBearerDefaults.AuthenticationScheme + " ", "");
            if (!string.IsNullOrEmpty(token))
            {
                var jwtHandler = new JwtSecurityTokenHandler();
                var options = AppSettingHelper.GetOptions<Common.Appsetting.SingleTokenOptions>();
                var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(options.SigningKey));
                // 创建一个TokenValidationParameters对象，用于配置JWT验证的参数
                var tokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = signingKey,
                    ValidateLifetime = true,
                    ValidateIssuer = true,
                    ValidIssuer = options.Issuer, //发行人
                    ValidateAudience = true,
                    ValidAudience = options.Audience, //订阅人
                    ClockSkew = TimeSpan.FromSeconds(0),//时间偏移量，过期了还能用
                    RequireExpirationTime = true
                };
                // 验证JWT并获取ClaimsPrincipal对象
                var vilidate = await jwtHandler.ValidateTokenAsync(token, tokenValidationParameters);
                if (vilidate.IsValid)
                {
                    var principal = new ClaimsPrincipal(vilidate.ClaimsIdentity);
                    var ticket = new AuthenticationTicket(principal, SingleTokenDefaults.AuthenticationScheme);
                    return await Task.FromResult(AuthenticateResult.Success(ticket));
                }
                else
                {
                    return await Task.FromResult(AuthenticateResult.Fail("ticket"));
                }
            }
            else
            {
                //获取token并且解析出token，判断在在线用户中是否存在
                return await Task.FromResult(AuthenticateResult.Fail("登录过期，请重新登录！"));
            }
        }

        protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
        {
            var result = new ApiResult
            {
                Status = StatusCodeConst.AuthRefreshTokenStatusCode,
                Message = StatusCodeConst.AuthRefreshTokenMessage,
                Url = Context.Request.Path
            };
            Context.Response.Headers.TryAdd(AuthHeaderTypeConst.TokenStatus, StatusCodeConst.AuthRefreshTokenStatusCode.ToString());
            Context.Response.StatusCode = StatusCodes.Status401Unauthorized;
            Context.Response.ContentType = MediaTypeNames.Application.Json;
            await Context.Response.WriteAsync(result.ToJson(true));
        }

        protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)
        {
            var result = new ApiResult
            {
                Status = StatusCodeConst.AuthForbiddenStatusCode,
                Message = StatusCodeConst.AuthForbiddenMessage,
                Url = Context.Request.Path
            };
            Context.Response.StatusCode = StatusCodes.Status403Forbidden;
            Context.Response.ContentType = MediaTypeNames.Application.Json;
            await Context.Response.WriteAsync(result.ToJson(true));
        }
    }

    public class SingleTokenDefaults
    {
        public const string AuthenticationScheme = "SingleTokenScheme";
        //public const string AuthenticationDisplayScheme = "SingleTokenDisplayScheme";
    }

    public class SingleTokenOptions : AuthenticationSchemeOptions
    {
        public string TokenHeaderName { get; set; }
    }
}
